/*
 * Copyright (c) Huawei Technologies Co., Ltd. 2021-2021. All rights reserved.
 * Description: Signature Verify CBB Library
 * Author: zhanghui
 * Create: 2021
 * History: 2021/01/01 reconstruction by zhanghui
 */
#include "../cmscbb_common/cmscbb_pem_util.h"
#include "cmscbb_sdk.h"
#include "../cms/cmscbb_cms_parse.h"
#include "../cmscbb_common/cmscbb_base64.h"
#include "../cmscbb_common/cmscbb_common.h"
#include "../cmscbb_common/cmscbb_list.h"
#include "../x509/cmscbb_x509.h"

#if CMSCBB_WITHOUT_SECUREC == 0
#include "securec.h"
#endif

#if CMSCBB_SUPPORT_PEM
#define CVB_MIN_PEM_LEN 38  /* sizeof("-----BEGIN XXX-----\r\n-----END XXX-----") */
#define CVB_PEM_SYMBOL "-----BEGIN"
#define CVB_PEM_SYMBOL_END "-----END"
#define CVB_PEM_SPLIT "-----"
#define CVB_PEM_SYMBOL_CMS "-----BEGIN CMS-----"
#define CVB_PEM_SYMBOL_CMS_END "-----END CMS-----"
#define CVB_PEM_SYMBOL_CMS_LEN 19
#define CVB_PEM_SYMBOL_PKCS7 "-----BEGIN PKCS7-----"
#define CVB_PEM_SYMBOL_PKCS7_END "-----END PKCS7-----"
#define CVB_PEM_SYMBOL_PKCS7_LEN 21
#define CVB_PEM_SYMBOL_CERT "-----BEGIN CERTIFICATE-----"
#define CVB_PEM_SYMBOL_CERT_END "-----END CERTIFICATE-----"
#define CVB_PEM_SYMBOL_CERT_LEN 27
#define CVB_PEM_SYMBOL_CRL "-----BEGIN X509 CRL-----"
#define CVB_PEM_SYMBOL_CRL_END "-----END X509 CRL-----"
#define CVB_PEM_SYMBOL_CRL_LEN 24

/*
 * Prototype    : InternalBase64Decode
 * Description  : decode base64 stream
 * Params
 *   [IN] pszB64Begin: begin of base64 stream
 *   [IN] pszB64End: end of base64 stream
 *   [OUT] decodeRes: decode res
 *   [OUT] decodeResLen: the length of decode res
 * Return Value : CVB_STATIC CMSCBB_ERROR_CODE
 *   Date              Author     Modification
 *   2015/11/10 11:47  tangzonglei  Create
 */
CVB_STATIC CMSCBB_ERROR_CODE InternalBase64Decode(const CVB_CHAR* b64Begin, CVB_UINT32 length,
    CVB_BYTE** decodeRes, CVB_UINT32* decodeResLen)
{
    CVB_UINT32 derLen = 0;
    CVB_BYTE* der = CVB_NULL;
    CMSCBB_ERROR_CODE ret;

    ret = CmscbbBase64Decode(b64Begin, length, CVB_NULL, &derLen);
    if (CVB_FAILED(ret)) {
        CVB_LOG_ERROR(ret, CVB_NULL);
        return ret;
    }
    if (derLen == 0) {
        CVB_LOG_ERROR(CMSCBB_ERR_PKI_CMS_INVALID_PEM, CVB_NULL);
        return (CMSCBB_ERR_PKI_CMS_INVALID_PEM);
    }

    ret = CmscbbMalloc((CVB_VOID**)&der, derLen);
    if (CVB_FAILED(ret)) {
        CVB_LOG_ERROR(ret, CVB_NULL);
        return ret;
    }

    ret = CmscbbBase64Decode(b64Begin, length, der, &derLen);
    if (CVB_FAILED(ret)) {
        CVB_LOG_ERROR(ret, CVB_NULL);
        CmscbbFreeWithNullCheck(der);
        return ret;
    }

    *decodeRes = der;
    *decodeResLen = derLen;
    return CVB_SUCCESS;
}

/*
 * Prototype    : InternalPemDecodeCert
 * Description  : decode cert with PEM format
 * Params
 *   [IN] rawSet: raw bytes set of certificate and crl
 *   [IN] begin: the certificate base64 begin location
 *   [IN] encodedLen: length of encode
 *   [OUT] cert: X509 Certificate
 * Return Value : CMSCBB_ERROR_CODE
 *   Date              Author     Modification
 *   2015/11/10 15:00  tangzonglei  Create
 */
CVB_STATIC CMSCBB_ERROR_CODE InternalPemDecodeCert(CmscbbListDummy* rawSet, const CVB_CHAR* begin,
    CVB_UINT32 encodedLen, CmscbbX509Cert** cert)
{
    CMSCBB_ERROR_CODE ret;
    const CVB_CHAR* cerB64Begin = CVB_NULL;
    const CVB_CHAR* cerB64End = CVB_NULL;
    CVB_BYTE* der = CVB_NULL;
    CVB_UINT32 derLen = 0;
    CVB_UINT32 decoded = 0;

    if (CmscbbStrNCmp(begin, (const CVB_CHAR*)CVB_PEM_SYMBOL_CERT, CVB_PEM_SYMBOL_CERT_LEN) != 0) {
        return CMSCBB_ERR_PKI_CMS_INVALID_PEM;
    }
    cerB64Begin = begin + CVB_PEM_SYMBOL_CERT_LEN + 1;

    cerB64End = CmscbbStrStr(begin, (const CVB_CHAR*)CVB_PEM_SYMBOL_CERT_END);
    if (cerB64End == CVB_NULL || (CVB_UINT32)(cerB64End - cerB64Begin) > encodedLen) {
        CVB_LOG_ERROR(CMSCBB_ERR_PKI_CMS_INVALID_PEM, CVB_NULL);
        return (CMSCBB_ERR_PKI_CMS_INVALID_PEM);
    }

    ret = InternalBase64Decode(cerB64Begin, (CVB_UINT32)(cerB64End - cerB64Begin), &der, &derLen);
    if (CVB_FAILED(ret)) {
        CVB_LOG_ERROR(ret, CVB_NULL);
        return CMSCBB_ERR_PKI_CMS_INVALID_PEM;
    }

    ret = CmscbbX509DecodeCert(der, derLen, cert, &decoded);
    CVB_GOTO_ERR_IF_FAIL_LOG(ret);

    ret = CMSCBB_LIST_ADD(rawSet, der);
    CVB_GOTO_ERR_IF_FAIL_LOG(ret);

    return CVB_SUCCESS;
CVB_ERR:
    CmscbbFreeWithNullCheck(der);
    if (cert != CVB_NULL) {
        CmscbbX509FreeCert(*cert);
        *cert = CVB_NULL;
    }
    return ret;
}

/*
 * Prototype    : InternalPemDecodeCrl
 * Description  : decode crl with PEM format
 * Params
 *   [IN] rawSet: raw bytes set of certificate and crl
 *   [IN] begin: the certificate base64 begin location
 *   [IN] encoded: length of encode
 *   [OUT] crl: X509 Certificate
 * Return Value : CMSCBB_ERROR_CODE
 *   Date              Author     Modification
 *   2015/11/10 15:01  tangzonglei  Create
 */
CVB_STATIC CMSCBB_ERROR_CODE InternalPemDecodeCrl(CmscbbListDummy* rawSet, const CVB_CHAR* begin, CVB_UINT32 encoded,
    CmscbbX509Crl** crl)
{
    CMSCBB_ERROR_CODE ret;
    const CVB_CHAR* b64Begin = CVB_NULL;
    const CVB_CHAR* b64End = CVB_NULL;
    CVB_BYTE* der = CVB_NULL;
    CVB_UINT32 derLen = 0;
    CVB_UINT32 decoded = 0;

    if (CmscbbStrNCmp(begin, (const CVB_CHAR*)CVB_PEM_SYMBOL_CRL, CVB_PEM_SYMBOL_CRL_LEN) != 0) {
        return CMSCBB_ERR_PKI_CMS_INVALID_PEM;
    }
    b64Begin = begin + CVB_PEM_SYMBOL_CRL_LEN;

    b64End = CmscbbStrStr(begin, (const CVB_CHAR*)CVB_PEM_SYMBOL_CRL_END);
    if (b64End == CVB_NULL || (CVB_UINT32)(b64End - b64Begin) > encoded) {
        CVB_LOG_ERROR(CMSCBB_ERR_PKI_CMS_INVALID_PEM, CVB_NULL);
        return (CMSCBB_ERR_PKI_CMS_INVALID_PEM);
    }

    ret = InternalBase64Decode(b64Begin, (CVB_UINT32)(b64End - b64Begin), &der, &derLen);
    if (CVB_FAILED(ret)) {
        CVB_LOG_ERROR(ret, CVB_NULL);
        return CMSCBB_ERR_PKI_CMS_INVALID_PEM;
    }

    ret = CmscbbX509DecodeCrl(der, derLen, crl, &decoded);
    CVB_GOTO_ERR_IF_FAIL_LOG(ret);

    ret = CMSCBB_LIST_ADD(rawSet, der);
    CVB_GOTO_ERR_IF_FAIL_LOG(ret);

    return CVB_SUCCESS;
CVB_ERR:
    CmscbbFreeWithNullCheck(der);
    if (crl != NULL) {
        CmscbbX509FreeCrl(*crl);
        *crl = NULL;
    }
    return ret;
}

/*
 * Prototype    : InternalAddPemCertToList
 * Description  : Add cert with PEM format into list
 * Params
 *   [IN] rawSet: raw bytes set of certificate and crl
 *   [IN] begin: the certificate base64 begin location
 *   [IN] length: the length of certificate base64
 *   [IN,OUT] certList: a list of X509 certificate
 * Return Value : CMSCBB_ERROR_CODE
 *   Date              Author     Modification
 *   2015/11/10 15:02  tangzonglei  Create
 */
CVB_STATIC CMSCBB_ERROR_CODE InternalAddPemCertToList(CmscbbListDummy* rawSet, const CVB_CHAR* begin, CVB_UINT32 length,
    LIST_OF(CmscbbX509Cert)* certList)
{
    CMSCBB_ERROR_CODE ret;
    CmscbbX509Cert* cert = CVB_NULL;
    ret = InternalPemDecodeCert(rawSet, begin, length, &cert);
    if (ret == CVB_SUCCESS && cert != CVB_NULL) {
        if (certList == CVB_NULL) {
            /* ignore cert when the input list is NULL */
            CmscbbX509FreeCert(cert);
        } else {
            ret = CMSCBB_LIST_ADD(certList, cert);
            if (ret != CVB_SUCCESS) {
                CmscbbX509FreeCert(cert);
            }
        }
    }

    return CVB_SUCCESS;
}

/*
 * Prototype    : InternalAddPemCrlToList
 * Description  : Add crl with PEM format into list.
 * Params
 *   [IN] rawSet: raw bytes set of certificate and crl
 *   [IN] begin: the certificate base64 begin location
 *   [IN] length: the length of certificate base64
 *   [IN,OUT] crlList: a list of X509 certificate
 * Return Value : CMSCBB_ERROR_CODE
 *   Date              Author     Modification
 *   2015/11/10 15:03  tangzonglei  Create
 */
CVB_STATIC CMSCBB_ERROR_CODE InternalAddPemCrlToList(CmscbbListDummy* rawSet, const CVB_CHAR* begin, CVB_UINT32 length,
    LIST_OF(CmscbbX509Crl)* crlList)
{
    CMSCBB_ERROR_CODE ret;
    CmscbbX509Crl* crl = CVB_NULL;
    ret = InternalPemDecodeCrl(rawSet, begin, length, &crl);
    if (ret == CVB_SUCCESS && crl != CVB_NULL) {
        if (crlList == CVB_NULL) {
            /* ignore crl when the input list is NULL */
            CmscbbX509FreeCrl(crl);
        } else {
            ret = CMSCBB_LIST_ADD(crlList, crl);
            if (ret != CVB_SUCCESS) {
                CmscbbX509FreeCrl(crl);
            }
        }
    }
    return CVB_SUCCESS;
}

/*
 * Prototype    : InternalDecodePemCertCrl
 * Description  : decode crl-bundle with PEM format, which contains both crl list and cert list
 * Params
 *   [IN] rawSet: raw bytes set of certificate and crl
 *   [IN] content: The data for the signature content
 *   [IN] contentLength: the length of signature content
 *   [IN,OUT] certList: a list of X509 certificate
 *   [IN,OUT] crlList: a list of X509 crl
 * Return Value : CMSCBB_ERROR_CODE
 *   Date              Author     Modification
 *   2015/11/10 15:03  tangzonglei  Create
 */
CVB_STATIC CMSCBB_ERROR_CODE InternalDecodePemCertCrl(CmscbbListDummy* rawSet, const CVB_BYTE* content,
    CVB_UINT32 contentLength, LIST_OF(CmscbbX509Cert)* certList, LIST_OF(CmscbbX509Crl)* crlList)
{
    CMSCBB_ERROR_CODE ret;
    const CVB_CHAR* begin = (const CVB_CHAR*)content;
    const CVB_CHAR* end = CVB_NULL;

    if (content == CVB_NULL || contentLength == 0) {
        CVB_LOG_ERROR(CMSCBB_ERR_CONTEXT_INVALID_PARAM, CVB_NULL);
        return CMSCBB_ERR_CONTEXT_INVALID_PARAM;
    }

    begin = CmscbbStrStr(begin, (const CVB_CHAR*)CVB_PEM_SYMBOL);
    while (begin != CVB_NULL) {
        const CVB_CHAR* types = begin + 11;
        end = CmscbbStrStr(begin, (const CVB_CHAR*)CVB_PEM_SYMBOL_END);
        if (end == CVB_NULL) {
            CVB_LOG_ERROR(CMSCBB_ERR_PKI_CMS_INVALID_PEM, CVB_NULL);
            return (CMSCBB_ERR_PKI_CMS_INVALID_PEM);
        }

        end += 8; /* 8 is the length of CVB_PEM_SYMBOL_END */
        end = CmscbbStrStr(end, (const CVB_CHAR*)CVB_PEM_SPLIT);
        if (end == CVB_NULL) {
            CVB_LOG_ERROR(CMSCBB_ERR_PKI_CMS_INVALID_PEM, CVB_NULL);
            return (CMSCBB_ERR_PKI_CMS_INVALID_PEM);
        }

        end += 5; /* 5 is the length of CVB_PEM_SPLIT */
        if (CmscbbStrNCmp(types, (const CVB_CHAR*)"CERTIFICATE", 11) == 0) { /* 11 is num of char to compare */
            ret = InternalAddPemCertToList(rawSet, begin, (CVB_UINT32)(begin - end), certList);
            if (CVB_FAILED(ret)) {
                CVB_LOG_ERROR(ret, CVB_NULL);
                return ret;
            }
        }
        if (CmscbbStrNCmp(types, (const CVB_CHAR*)"X509 CRL", 8) == 0) { /* 8 is number of characters to compare */
            ret = InternalAddPemCrlToList(rawSet, begin, (CVB_UINT32)(begin - end), crlList);
            if (CVB_FAILED(ret)) {
                CVB_LOG_ERROR(ret, CVB_NULL);
                return ret;
            }
        }
        begin = CmscbbStrStr(end, (const CVB_CHAR*)CVB_PEM_SYMBOL);
    }

    return CVB_SUCCESS;
}


/*
 * Prototype    : CmscbbPemDecodeCms
 * Description  : decode PEM format CMS
 * Params
 *   [IN] vrf: data for verify context
 *   [IN] pszPem: pem header
 *   [IN] nSigLength: signed of  length
 *   [OUT] p7signed: pkcs7 singed content
 * Return Value : CMSCBB_ERROR_CODE
 *   Date              Author     Modification
 *   2015/11/10 12:01  tangzonglei  Create
 */
CMSCBB_ERROR_CODE CmscbbPemDecodeCms(CmscbbVrf* vrf, const CVB_CHAR* pszPem, CVB_UINT32 nSigLength,
    CmscbbPkcs7Content** p7signed)
{
    CMSCBB_ERROR_CODE ret;
    const CVB_CHAR* pszB64Begin = CVB_NULL;
    const CVB_CHAR* pszB64End = CVB_NULL;
    CVB_BYTE* der = CVB_NULL;
    CVB_UINT32 derLen = 0;
    CVB_UINT32 nDecoded = 0;
    CVB_UINT32 nEncoded;

    /* check the PEM header, get base64 encoded content */
    if (CmscbbStrNCmp(pszPem, (const CVB_CHAR*)CVB_PEM_SYMBOL_CMS, CVB_PEM_SYMBOL_CMS_LEN) == 0) {
        pszB64Begin = pszPem + CVB_PEM_SYMBOL_CMS_LEN;

        pszB64End = CmscbbStrStr(pszPem, (const CVB_CHAR*)CVB_PEM_SYMBOL_CMS_END);
        if (pszB64End == CVB_NULL) {
            CVB_LOG_ERROR(CMSCBB_ERR_PKI_CMS_INVALID_PEM, CVB_NULL);
            return CMSCBB_ERR_PKI_CMS_INVALID_PEM;
        }
    } else if (CmscbbStrNCmp(pszPem, (const CVB_CHAR*)CVB_PEM_SYMBOL_PKCS7, CVB_PEM_SYMBOL_PKCS7_LEN) == 0) {
        pszB64Begin = pszPem + CVB_PEM_SYMBOL_PKCS7_LEN;
        pszB64End = CmscbbStrStr(pszPem, (const CVB_CHAR*)CVB_PEM_SYMBOL_PKCS7_END);
        if (pszB64End == CVB_NULL) {
            CVB_LOG_ERROR(CMSCBB_ERR_UNDEFINED, CVB_NULL);
            return (CMSCBB_ERR_UNDEFINED);
        }
    } else {
        return CMSCBB_ERR_PKI_CMS_INVALID_PEM;
    }

    nEncoded = (CVB_UINT32)(pszB64End - pszB64Begin);
    if (nEncoded > nSigLength) {
        CVB_LOG_ERROR(CMSCBB_ERR_PKI_CMS_INVALID_PEM, CVB_NULL);
        return (CMSCBB_ERR_PKI_CMS_INVALID_PEM);
    }

    ret = InternalBase64Decode(pszB64Begin, nEncoded, &der, &derLen);
    if (CVB_FAILED(ret)) {
        CVB_LOG_ERROR(ret, CVB_NULL);
        return ret;
    }

    ret = CmscbbPkcs7DecodeSigned(der, derLen, p7signed, &nDecoded);
    CVB_GOTO_ERR_IF_FAIL_LOG(ret);

    ret = CMSCBB_LIST_ADD(&(vrf->rawSet), der);
    CVB_GOTO_ERR_IF_FAIL_LOG(ret);

    return CVB_SUCCESS;
CVB_ERR:
    CmscbbFreeWithNullCheck(der);
    if (p7signed != CVB_NULL) {
        CmscbbPkcs7FreeSigned(*p7signed);
        *p7signed = CVB_NULL;
    }
    return ret;
}
#endif

/*
 * Prototype    : CmscbbDecodeCertCrl
 * Description  : decode crl-bundle, which contains both crl list and cert list
 * Params
 *   [IN] rawSet: raw bytes set of certificate and crl
 *   [IN] content: The data for the signature content
 *   [IN] contentLength: length of the signature content
 *   [IN,OUT] certList: list of X509 certificate
 *   [IN,OUT] crlList: list of X509 crl
 * Return Value : CMSCBB_ERROR_CODE
 *   Date              Author     Modification
 *   2015/11/10 14:59  tangzonglei  Create
 */
CMSCBB_ERROR_CODE CmscbbDecodeCertCrl(CmscbbListDummy* rawSet, const CVB_BYTE* content,
    CVB_UINT32 contentLength, LIST_OF(CmscbbX509Cert)* certList, LIST_OF(CmscbbX509Crl)* crlList)
{
#if CMSCBB_SUPPORT_PEM
    CVB_BOOL isPem = CVB_FALSE;

    if (contentLength < CVB_MIN_PEM_LEN) {
        return CMSCBB_ERR_PKI_CMS_INVALID_PEM;
    }

    if (CmscbbStrNCmp((const CVB_CHAR*)content, (const CVB_CHAR*)CVB_PEM_SYMBOL,
        (CVB_SIZE_T)CmscbbStrlen((const CVB_CHAR*)CVB_PEM_SYMBOL)) == 0) {
        isPem = CVB_TRUE;
    }

    if (isPem) {
        CMSCBB_ERROR_CODE ret;
        CVB_BYTE* pemContent = CVB_NULL;

        /* The string must end with 0 to ensure Strstr is not crossed */
        ret = CmscbbMallocWith0((CVB_VOID**)&pemContent, contentLength + 1);
        if (CVB_FAILED(ret)) {
            CVB_LOG_DEBUG(ret, CVB_NULL);
            return ret;
        }
        ret = (CMSCBB_ERROR_CODE)memcpy_s((CVB_VOID*)pemContent, contentLength, (const CVB_VOID*)content,
            contentLength);
        if (CVB_FAILED(ret)) {
            CmscbbFreeWithNullCheck((CVB_VOID*)pemContent);
            return ret;
        }

        ret = InternalDecodePemCertCrl(rawSet, pemContent, contentLength, certList, crlList);
        CmscbbFreeWithNullCheck((CVB_VOID*)pemContent);
        return ret;
    } else
#endif
    {
        return CmscbbDecodeStreamCertCrl(rawSet, content, contentLength, certList, crlList);
    }
}

CVB_STATIC CMSCBB_ERROR_CODE InternalDecodeStreamListAddCrl(const CVB_BYTE** encoded, CVB_UINT32 decodedLength,
    CVB_UINT32* remainLength, CmscbbX509Crl** crl, LIST_OF(CmscbbX509Crl)* crlList)
{
    CMSCBB_ERROR_CODE ret;
    CVB_UINT32 remainLen = *remainLength;

    if (crlList != CVB_NULL) {
        ret = CMSCBB_LIST_ADD(crlList, *crl);
        if (CVB_FAILED(ret)) {
            return ret;
        }
    } else {
        CmscbbX509FreeCrl(*crl);
    }

    *encoded += decodedLength;
    remainLen -= decodedLength;
    *remainLength = remainLen;
    *crl = CVB_NULL;

    return CVB_SUCCESS;
}

CVB_STATIC CMSCBB_ERROR_CODE InternalDecodeStreamListAddCert(const CVB_BYTE** pbEncoded, CVB_UINT32 nDecodedLength,
    CVB_UINT32* nRemainLength, CmscbbX509Cert** cert, LIST_OF(CmscbbX509Cert)* pCertList)
{
    CMSCBB_ERROR_CODE ret;
    CVB_UINT32 nnRemainLength = *nRemainLength;

    if (pCertList != CVB_NULL) {
        ret = CMSCBB_LIST_ADD(pCertList, *cert);
        if (CVB_FAILED(ret)) {
            return ret;
        }
    } else {
        CmscbbX509FreeCert(*cert);
    }

    *pbEncoded += nDecodedLength;
    nnRemainLength -= nDecodedLength;
    *nRemainLength = nnRemainLength;
    *cert = CVB_NULL;

    return CVB_SUCCESS;
}

CMSCBB_ERROR_CODE CmscbbDecodeStreamCertCrl(CmscbbListDummy* rawSet, const CVB_BYTE* content,
    CVB_UINT32 contentLength, LIST_OF(CmscbbX509Cert)* certList, LIST_OF(CmscbbX509Crl)* crlList)
{
    CMSCBB_ERROR_CODE ret;
    const CVB_BYTE* encoded = content;
    CVB_UINT32 decodedLength = 0;
    CmscbbX509Cert* cert = CVB_NULL;
    CmscbbX509Crl* crl = CVB_NULL;
    CVB_UINT32 remainLength = contentLength;
    CVB_BYTE* pbCopy = CVB_NULL;

#if CMSCBB_CACHE_ASN_DATA
    ret = CmscbbMalloc((CVB_VOID**)&pbCopy, contentLength);
    CVB_GOTO_ERR_IF_FAIL(ret);

    ret = (CMSCBB_ERROR_CODE)memcpy_s(pbCopy, contentLength, content, contentLength);
    CVB_GOTO_ERR_IF_FAIL_LOG(ret);

    encoded = pbCopy;
#endif

    while (remainLength > 0) {
        ret = CmscbbX509DecodeCert(encoded, remainLength, &cert, &decodedLength);
        if (cert != CVB_NULL) {
            ret = InternalDecodeStreamListAddCert(&encoded, decodedLength, &remainLength, &cert, certList);
            CVB_GOTO_ERR_IF_FAIL_LOG(ret);
            continue;
        }

        ret = CmscbbX509DecodeCrl(encoded, remainLength, &crl, &decodedLength);
        if (crl != CVB_NULL) {
            ret = InternalDecodeStreamListAddCrl(&encoded, decodedLength, &remainLength, &crl, crlList);
            CVB_GOTO_ERR_IF_FAIL_LOG(ret);
            continue;
        }

        break;
    }

    /* Provides limited fault tolerance, allowing for a certain amount of redundant data */
    if (ret != CVB_SUCCESS && remainLength > 32) {  /* 32 is the length of redundant data */
        CVB_GOTO_ERR_IF_FAIL(ret);
    }
    ret = CVB_SUCCESS;
#if CMSCBB_CACHE_ASN_DATA
    ret = CMSCBB_LIST_ADD(rawSet, pbCopy);
    CVB_GOTO_ERR_IF_FAIL(ret);
#endif
    (void)rawSet;
    return ret;
CVB_ERR:
    CmscbbX509FreeCert(cert);
    CmscbbX509FreeCrl(crl);
    CmscbbFreeWithNullCheck(pbCopy);
    return ret;
}

#if CMSCBB_SUPPORT_CRL_COMPARE
CMSCBB_ERROR_CODE CmscbbDecodeAndCheckCrl(CmscbbListDummy* rawSet, const CVB_BYTE* content,
    CVB_UINT32 contentLength, LIST_OF(CmscbbX509Cert)* certList, LIST_OF(CmscbbX509Crl)* crlList)
{
    CMSCBB_ERROR_CODE ret;
    ret = CmscbbDecodeCertCrl(rawSet, content, contentLength, certList, crlList);
    if (ret != CVB_SUCCESS) {
        CVB_LOG_ERROR(ret, "Decode CRL failed or crlList is empty");
        return CMSCBB_ERR_PKI_CRL_DECODE;
    }

    if (crlList->num > MAX_CRL_SUPPORT || crlList->num == 0) {
        CVB_LOG_ERROR(ret, "Decode CRL failed.");
        return CMSCBB_ERR_PKI_CRL_TOO_MUCH;
    }

    return ret;
}
#endif /* CMSCBB_SUPPORT_CRL_COMPARE */

CMSCBB_ERROR_CODE CmscbbDecodeSignature(CmscbbVrf* vrf, const CVB_BYTE* signature, CVB_UINT32 sigLen,
    CmscbbPkcs7Content** p7signed)
{
    CMSCBB_ERROR_CODE ret;
    CVB_UINT32 decodedLen = 0;

#if CMSCBB_SUPPORT_PEM
    if (sigLen < CVB_MIN_PEM_LEN) {
        return CMSCBB_ERR_PKI_CMS_INVALID_PEM;
    }

    if (CmscbbStrNCmp((const CVB_CHAR*)signature, (const CVB_CHAR*)CVB_PEM_SYMBOL,
                      (CVB_SIZE_T)CmscbbStrlen((const CVB_CHAR*)CVB_PEM_SYMBOL)) == 0) {
        CVB_BYTE* pemContent = CVB_NULL;
        /* The string must end with 0 to ensure Strstr is not crossed */
        ret = CmscbbMallocWith0((CVB_VOID**)&pemContent, sigLen + 1);
        CVB_GOTO_ERR_WITH_LOG_IF(CVB_FAILED(ret), ret);

        ret = (CMSCBB_ERROR_CODE)memcpy_s((CVB_VOID*)pemContent, sigLen, (const CVB_VOID*)signature, sigLen);
        if (CVB_FAILED(ret)) {
            CmscbbFreeWithNullCheck((CVB_VOID*)pemContent);
            return ret;
        }
        ret = CmscbbPemDecodeCms(vrf, (const CVB_CHAR*)pemContent, sigLen, p7signed);
        CmscbbFreeWithNullCheck((CVB_VOID*)pemContent);
    } else {
        ret = CmscbbPkcs7DecodeSigned(signature, sigLen, p7signed, &decodedLen);
    }
#else
    ret = CmscbbPkcs7DecodeSigned(signature, sigLen, p7signed, &decodedLen);
#endif
    CVB_GOTO_ERR_WITH_LOG_IF((*p7signed == CVB_NULL), CMSCBB_ERR_PKI_CMS_NO_SIGNER_INFO);
    if (CVB_FAILED(ret)) {
        CmscbbPkcs7FreeSigned(*p7signed);
        CVB_LOG_ERROR(CMSCBB_ERR_PKI_CMS_NO_SIGNER_INFO, NULL);
        return CMSCBB_ERR_PKI_CMS_NO_SIGNER_INFO;
    }
    (void)vrf;
CVB_ERR:
    return ret;
}
